package com.titaniume.java2;

import com.titaniume.java1.Person;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @program: JavaSenior
 * @description:
 *
 *  调用运行时类中指定的结构：属性，方法，构造器
 * @author: renfei.huang
 * @create: 2021-10-30 17:33
 */
public class ReflectionTest {


    @Test
    public  void testField() throws NoSuchFieldException, IllegalAccessException, InstantiationException {

        Class clazz = Person.class;

        //创建运行时类的对象
        Person person = (Person)clazz.newInstance();

        //获取指定的属性 :要求运行时类中属性声明为public
        //通常不采用此方法
        Field id = clazz.getField("id");

        /*
        *
        *
        * 设置当前属性的值
        * set(): 参数一：指明当前设置哪个对象的属性 参数2： 将此属性设置为多少
        *
        * */
        id.set(person,1001);

        /*
        *
        * 获取当前属性的值
        * get() :参数一：获取哪个对象当前属性的值
        *
        * */
        int pid =(int) id.get(person);
        System.out.println(pid);
    }


    // 如何操作运行时类中的指定属性 --需要掌握
    @Test
    public  void  testField1() throws IllegalAccessException, InstantiationException, NoSuchFieldException {

       Class clazz =  Person.class;
        //创建运行时类的对象
        Person person = (Person)clazz.newInstance();

        //1.getDeclaredField(String fieldName)：获取运行时类中指定变量名的属性
        Field name = clazz.getDeclaredField("name");

        //2. 保证当前属性是可访问的
        name.setAccessible(true);

        //3.获取，设置指定对象的此属性值
        name.set(person,"tom");
        System.out.println(name.get(person));
    }


    // 如何操作运行时类中的指定方法 --需要掌握

    @Test
    public  void testMethod() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        Class clazz  = Person.class;

        //创建运行时类的对象
        Person person = (Person)clazz.newInstance();

        //1.获取指定的某个方法
        /*
        * getDeclaredMethod():参数一： 指明获取方法名称 参数二：指明获取方法的形参列表
        * */
        Method show = clazz.getDeclaredMethod("show", String.class);


        //2.保证当前方法是可访问的
        show.setAccessible(true);

        /*
        * invoke() : 参数一: 方法的调用者  参数二： 给方法形参的实参
        * invoke() 的返回值即为对应类中调用的方法的返回值
        *
        * */
       Object returnValue =   show.invoke(person,"CHN"); //String nation = person.show("CHN");
       System.out.println(returnValue);

        System.out.println("如何调用静态方法");
        // private  static  void showDesc()
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果调用运行时的类中的方法没有返回值，则invoke()返回null
        Object returnVal =  showDesc.invoke(Person.class);
        //静态属性 invoke 参数 可以传也可以设置为null
//        Object returnVal =  showDesc.invoke(null);
        System.out.println(returnVal); //null

    }


    /*
    * 如何调用运行时类中指定的构造器 (不通用) 少用
    *
    * */
    @Test
    public  void testConstructor() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {


        Class clazz  = Person.class;

        //创建运行时类的对象
        Person person = (Person)clazz.newInstance();


        //
        /* private  Person(String name)
        * 1.获取指定的构造器
        * getDeclaredConstructor() 参数：指明构造器的参数列表
        * */
        Constructor constructor = clazz.getDeclaredConstructor(String.class);


        //2保证此构造器是可访问的
        constructor.setAccessible(true);

        //3.调用此构造器创建运行时类的对象
        Person person1 = (Person)constructor.newInstance("tom");

        System.out.println(person1);
    }

}
